package cn.thornbird.orgsync.model.certificate;

import cn.thornbird.orgsync.util.EncryptUtil;
import cn.thornbird.orgsync.util.ReflectUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public abstract class AppCertificate {

    public AppCertificate() {
        addFields();
    }

    protected List<String> fields = new ArrayList<>();

    public static <T> T deserialize(Class<T> clazz, String text) {
        T certificate = null;
        int position = text.indexOf("(");
        String[] values = (text.substring(position + 1, text.length() - 1)).split(",");
        String[] params = new String[values.length];
        AtomicInteger index = new AtomicInteger();
        Arrays.stream(values).forEach(value -> params[index.getAndIncrement()] = value.substring(value.indexOf("=") + 1));
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor constructor : constructors) {
            if (constructor.getParameterTypes().length == params.length) {
                try {
                    certificate = (T) constructor.newInstance(params);
                } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
                    log.error("error", e);
                }
            }
        }
        return certificate;
    }

    @Override
    public boolean equals(Object object) {
        if (object instanceof AppCertificate) {
            return getMd5Key().equals(((AppCertificate) object).getMd5Key());
        }
        return false;
    }

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(getClass().getName());
        stringBuilder.append("(");
        for (int i = 0, count = fields.size(); i < count; i++) {
            String field = fields.get(i);
            Object value = ReflectUtil.getValue(this, field);
            stringBuilder.append(value == null ? "" : value.toString());
            stringBuilder.append(i < count - 1 ? "," : ")");
        }
        return stringBuilder.toString();
    }

    public String getMd5Key() {
        StringBuilder stringBuilder = new StringBuilder();
        String className = getClass().getName();
        for (String field : fields) {
            Object value = ReflectUtil.getValue(this, field);
            stringBuilder.append(value == null ? "" : value.toString());
            stringBuilder.append(",");
        }
        stringBuilder.append(className);
        return EncryptUtil.md5(toString());
    }

    protected void addFields() { }

}
